Displaying Posts
================

In our blog application, a post may be displayed among a list of posts or by itself. The former is implemented as the `index` operation while the latter the `view` operation. In this section, we customize both operations to fulfill our initial requirements.


Customizing `view` Operation
----------------------------

The `view` operation is implemented by the `actionView()` method in `PostController`. Its display is generated by the `view` view with the view file `/wwwroot/blog/protected/views/post/view.php`.

Below is the relevant code implementing the `view` operation in `PostController`:

~~~
[php]
public function actionView()
{
	$post=$this->loadModel();
	$this->render('view',array(
		'model'=>$post,
	));
}

private $_model;

public function loadModel()
{
	if($this->_model===null)
	{
		if(isset($_GET['id']))
		{
			if(Yii::app()->user->isGuest)
				$condition='status='.Post::STATUS_PUBLISHED
					.' OR status='.Post::STATUS_ARCHIVED;
			else
				$condition='';
			$this->_model=Post::model()->findByPk($_GET['id'], $condition);
		}
		if($this->_model===null)
			throw new CHttpException(404,'The requested page does not exist.');
	}
	return $this->_model;
}
~~~

Our change mainly lies in the `loadModel()` method. In this method, we query the `Post` table according to the `id` GET parameter. If the post is not found or if it is not published or archived (when the user is a guest), we will throw a 404 HTTP error. Otherwise the post object is returned to `actionView()` which in turn passes the post object to the view script for further display.

> Tip: Yii captures HTTP exceptions (instances of [CHttpException]) and displays them in either predefined templates or customized error views. The skeleton application generated by `yiic` already contains a customized error view in `/wwwroot/blog/protected/views/site/error.php`. We can modify this file if we want to further customize the error display.

The change in the `view` script is mainly about ajdusting the formatting and styles of the post display. We will not go into details here. Interested readers may refer to `/wwwroot/blog/protected/views/post/view.php`.


Customizing `index` Operation
----------------------------

Like the `view` operation, we customize the `index` operation in two places: the `actionIndex()` method in `PostController` and the view file `/wwwroot/blog/protected/views/post/index.php`. We mainly need to add the support for displaying a list of posts that are associated with a specified tag.

Below is the modified `actionIndex()` method in `PostController`:

~~~
[php]
public function actionIndex()
{
	$criteria=new CDbCriteria(array(
		'condition'=>'status='.Post::STATUS_PUBLISHED,
		'order'=>'update_time DESC',
		'with'=>'commentCount',
	));
	if(isset($_GET['tag']))
		$criteria->addSearchCondition('tags',$_GET['tag']);

	$dataProvider=new CActiveDataProvider('Post', array(
		'pagination'=>array(
			'pageSize'=>5,
		),
		'criteria'=>$criteria,
	));

	$this->render('index',array(
		'dataProvider'=>$dataProvider,
	));
}
~~~

In the above, we first create a query criteria for retrieving post list. The criteria states that only published posts should be returned and they should be sorted according to their update time in descending order. Because when displaying a post in the list, we want to show how many comments the post has received, in the criteria we also specify to bring back `commentCount`, which if you remember, is a relation declared in `Post::relations()`.

In case when a user wants to see posts with a specific tag, we would add a search condition to the criteria to look for the specified tag.

Using the query criteria, we create a data provider, which mainly serves for three purposes. First, it does pagination of the data when too many results may be returned. Here we customize the pagination by setting the page size to be 5. Second, it does sorting according to the user request. And finally, it feeds the paginated and sorted data to widgets or view code for presentation.

After we finish with `actionIndex()`, we modify the `index` view as follows. Our change is mainly about adding the `h1` header when the user specifies to display posts with a tag.

~~~
[php]
<?php if(!empty($_GET['tag'])): ?>
<h1>Posts Tagged with <i><?php echo CHtml::encode($_GET['tag']); ?></i></h1>
<?php endif; ?>

<?php $this->widget('zii.widgets.CListView', array(
	'dataProvider'=>$dataProvider,
	'itemView'=>'_view',
	'template'=>"{items}\n{pager}",
)); ?>
~~~

Note that in the above, we use [CListView] to display the post list. This widget requires a partial view to display the detail of each individual post. Here we specify the partial view to be `_view`, which means the file `/wwwroot/blog/protected/views/post/_view.php`. In this view script, we can acccess the post instance being displayed via a local variable named `$data`.

